<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount, watch, computed } from 'vue'
import { useRouter } from 'vue-router'
import { showToast, showDialog, Icon, Popup } from 'vant'
import { useChatStore } from '@/store/chat'
import 'highlight.js/styles/github.css'
import ReferenceMaterial from './components/ReferenceMaterial.vue'
import WebBrowser from './components/WebBrowser.vue'
import SearchInput from './components/SearchInput.vue'
import MessageList from './components/MessageList.vue'
import WelcomeMessage from './components/WelcomeMessage.vue'

const router = useRouter()

type MessageType = {
  type: 'user' | 'ai';
  content: string;
} & (
  | { 
      hasThinking: true;
      thinking: {
        content: string;
        done: boolean;
        time: number;
        startTime?: number;
      };
      hasReferences?: boolean;
      references?: any[];
      referenceCount?: number;
    }
  | {
      hasThinking?: false;
      thinking?: undefined;
      hasReferences?: boolean;
      references?: any[];
      referenceCount?: number;
    }
);

const chatStore = useChatStore()

const historyMessages = ref<MessageType[]>([])

const sessionId = ref('')
const message = computed(() => chatStore.connectionState.searchMessage)
const loading = computed(() => chatStore.connectionState.searchLoading)
const error = computed(() => chatStore.connectionState.error)

const initSession = () => {
  if (chatStore.currentSearchSessionId) {
    sessionId.value = chatStore.currentSearchSessionId
    const savedMessages = chatStore.getCurrentSearchMessages()
    if (savedMessages && savedMessages.length > 0) {
      historyMessages.value = savedMessages
    }
  } else {
    sessionId.value = chatStore.generateSessionId()
    chatStore.currentSearchSessionId = sessionId.value
  }
}

initSession()

const goBack = () => {
  router.back()
}

const handleSearch = (searchText: string) => {
  historyMessages.value.push({
    type: 'user',
    content: searchText
  } as MessageType)
  
  const aiMessage: MessageType = {
    type: 'ai',
    content: '',
    hasThinking: false,
    hasReferences: false,
    references: [],
    referenceCount: 0
  }
  historyMessages.value.push(aiMessage)
  
  chatStore.sendSearchMessage(sessionId.value, searchText)
  scrollToBottom()
  shouldAutoScroll.value = true
  
  chatStore.saveSearchMessages(sessionId.value, historyMessages.value)
}

const handleStopStream = () => {
  chatStore.stopStream('search')
  
  const lastIndex = historyMessages.value.length - 1
  if (lastIndex >= 0 && historyMessages.value[lastIndex].type === 'ai') {
    const lastAIMessage = historyMessages.value[lastIndex]
    
    if (lastAIMessage.hasThinking && lastAIMessage.thinking) {
      const thinkingMessage = lastAIMessage as Extract<MessageType, { hasThinking: true }>;
      thinkingMessage.thinking.done = true;
      
      if (!thinkingMessage.thinking.time || thinkingMessage.thinking.time <= 0) {
        if (thinkingMessage.thinking.startTime) {
          const elapsedTime = Date.now() - thinkingMessage.thinking.startTime;
          thinkingMessage.thinking.time = Math.max(1, Math.round(elapsedTime / 1000));
        } else {
          thinkingMessage.thinking.time = 1;
        }
      }
    }
    
    if (!lastAIMessage.content && (!lastAIMessage.hasThinking || 
        (lastAIMessage.hasThinking && !lastAIMessage.thinking?.content))) {
      lastAIMessage.content = '回答已中断'
    }
  }
}

const clearHistory = () => {
  if (loading.value) {
    handleStopStream()
  }
  
  historyMessages.value = []
  chatStore.clearSearchMessage()
  
  chatStore.clearSearchMessages(sessionId.value)
  
  sessionId.value = chatStore.generateSessionId()
  chatStore.currentSearchSessionId = sessionId.value
}

const shouldAutoScroll = ref(true)
const isUserScrolling = ref(false)
const scrollTimer = ref<ReturnType<typeof setTimeout> | null>(null)
const chatContent = ref<HTMLDivElement>()

const scrollToBottom = () => {
  requestAnimationFrame(() => {
    if (chatContent.value) {
      chatContent.value.scrollTo({
        top: chatContent.value.scrollHeight,
        behavior: 'auto'
      });
    }
  });
}

const isScrolledToBottom = (): boolean => {
  if (!chatContent.value) return true
  
  const { scrollTop, scrollHeight, clientHeight } = chatContent.value
  return scrollHeight - scrollTop - clientHeight < 20
}

const handleScroll = () => {
  if (scrollTimer.value) {
    clearTimeout(scrollTimer.value)
  }
  isUserScrolling.value = true
  shouldAutoScroll.value = isScrolledToBottom()
  scrollTimer.value = setTimeout(() => {
    isUserScrolling.value = false
  }, 150)
}

const parseAIMessage = (msg: string) => {
  const result = {
    content: '',
    references: [] as any[],
    thinking: '',
    thinkingDone: false
  }
  
  try {
    let originalMsg = msg;
    const refMatch = originalMsg.match(/联网搜索结果: (.+?)(?=<think>|$)/s);
    if (refMatch && refMatch[1]) {
      try {
        // 提取JSON字符串
        let jsonText = refMatch[1].trim();
        
        // 使用正则表达式直接解析引用资料
        const refRegex = /\{title="([^"]*)"\s*,\s*url="([^"]*)"\s*,\s*content="([^"]*)"\}/g;
        let match;
        const refs = [];
        
        while ((match = refRegex.exec(jsonText)) !== null) {
          refs.push({
            title: match[1] || '',
            url: match[2] || '',
            content: match[3] || ''
          });
        }

        if (refs.length > 0) {
          result.references = refs;
        } else {
          console.log('使用备用方案解析引用资料');
          // 备用方案：尝试标准JSON解析
          try {
            // 替换带引号的属性名中的等号为冒号
            jsonText = jsonText.replace(/(\w+)="([^"]*)"/g, '"$1":"$2"');
            
            // 确保属性名有引号
            jsonText = jsonText.replace(/(\{|\,)\s*(\w+)\s*\:/g, '$1"$2":');
            
            // 处理内部的转义引号
            jsonText = jsonText.replace(/\\"/g, '"').replace(/"{/g, '{').replace(/}"/g, '}');
            
            // 处理双引号问题
            jsonText = jsonText.replace(/=\s*"/g, ':"').replace(/"\s*,/g, '",');
            
            // 在解析前检查是否符合JSON格式
            if (jsonText.startsWith('[{') && jsonText.endsWith('}]')) {
              const parsedRefs = JSON.parse(jsonText);
              
              if (Array.isArray(parsedRefs) && parsedRefs.length > 0) {
                result.references = parsedRefs.map(ref => ({
                  title: ref.title || '',
                  url: ref.url || '',
                  content: ref.content || ''
                }));
              }
            }
          } catch (jsonErr) {
            console.error('JSON解析失败:', jsonErr);
          }
        }
      } catch (e) {
        console.error('解析引用资料JSON失败:', e, '\n原始文本:', refMatch[1]);
      }
      
      // 从原始消息中移除引用资料部分，无论解析成功与否
      originalMsg = originalMsg.replace(/联网搜索结果: .+?(?=<think>|$)/s, '');
    }
    
    // 解析思考过程
    const thinkOpenTag = originalMsg.indexOf('<think>');
    const thinkCloseTag = originalMsg.indexOf('</think>');
    
    if (thinkOpenTag !== -1) {
      if (thinkCloseTag !== -1) {
        // 提取完整的思考内容
        result.thinking = originalMsg.substring(thinkOpenTag + 7, thinkCloseTag).trim();
        result.thinkingDone = true;
        
        // 从原始消息中移除思考过程部分
        originalMsg = originalMsg.replace(/<think>.*?<\/think>/s, '');
      } else {
        // 思考尚未完成，提取部分内容
        result.thinking = originalMsg.substring(thinkOpenTag + 7).trim();
        result.thinkingDone = false;
        
        // 此时还没有最终回答，清空原始消息
        originalMsg = '';
      }
    }
    
    // 剩余的内容就是最终的AI回答
    result.content = originalMsg.trim();
    
  } catch (e) {
    console.error('解析AI消息失败:', e);
  }
  
  return result;
}

const watchMessage = (): void => {
  if (message.value) {
    const lastIndex = historyMessages.value.length - 1;
    if (lastIndex >= 0 && historyMessages.value[lastIndex].type === 'ai') {
      const lastAIMessage = historyMessages.value[lastIndex];
      
      const parsedMessage = parseAIMessage(message.value);
      
      if (parsedMessage.references.length > 0) {
        lastAIMessage.references = parsedMessage.references;
        lastAIMessage.hasReferences = true;
        lastAIMessage.referenceCount = parsedMessage.references.length;
      }
      
      const hasThinkStartTag = message.value.includes('<think>');
      const hasThinkEndTag = message.value.includes('</think>');
      
      if (hasThinkStartTag && parsedMessage.thinking.trim() !== '') {
        if (!lastAIMessage.hasThinking) {
          const thinkingMessage: Extract<MessageType, { hasThinking: true }> = {
            ...lastAIMessage,
            hasThinking: true,
            thinking: {
              content: parsedMessage.thinking,
              done: hasThinkEndTag,
              time: 0,
              startTime: Date.now()
            }
          };
          
          historyMessages.value[lastIndex] = thinkingMessage;
        } else {
          const thinkingMessage = lastAIMessage as Extract<MessageType, { hasThinking: true }>;
          thinkingMessage.thinking.content = parsedMessage.thinking;
          
          if (hasThinkEndTag && !thinkingMessage.thinking.done) {
            thinkingMessage.thinking.done = true;
            
            if (thinkingMessage.thinking.startTime) {
              const elapsedTime = Date.now() - thinkingMessage.thinking.startTime;
              thinkingMessage.thinking.time = Math.max(1, Math.round(elapsedTime / 1000));
            } else {
              thinkingMessage.thinking.time = 3; 
            }
          }
        }
      } else if (!hasThinkStartTag && lastAIMessage.hasThinking) {
        const nonThinkingMessage: Extract<MessageType, { hasThinking?: false }> = {
          ...lastAIMessage,
          hasThinking: false,
          thinking: undefined
        };
        
        historyMessages.value[lastIndex] = nonThinkingMessage;
      }
      
      if (!hasThinkStartTag || hasThinkEndTag) {
        historyMessages.value[lastIndex].content = parsedMessage.content;
      }
      
      chatStore.saveSearchMessages(sessionId.value, historyMessages.value)
      
      if (shouldAutoScroll.value && !isUserScrolling.value) {
        scrollToBottom();
      }
    }
  }
}

const watchError = (): void => {
  if (error.value) {
    showToast(error.value)
    setTimeout(() => {
      chatStore.connectionState.error = ''
    }, 100)
  }
}

onMounted(() => {
  if (chatContent.value) {
    chatContent.value.addEventListener('scroll', handleScroll)
  }
})

onBeforeUnmount(() => {
  if (chatContent.value) {
    chatContent.value.removeEventListener('scroll', handleScroll)
  }
  if (scrollTimer.value) {
    clearTimeout(scrollTimer.value)
  }
})

watch(message, () => {
  watchMessage();
});

watch(error, (newVal) => {
  if (newVal) {
    watchError()
  }
})
watch(loading, (newVal: boolean, oldVal: boolean) => {
  if (newVal === false && oldVal === true) {
    shouldAutoScroll.value = true
  }
})

const showReferences = ref(false)
const selectedReference = ref<any>(null)
const showExternalSite = ref(false)
const selectedReferences = ref<any[]>([]);

const openReferences = (references: any[]) => {
  selectedReferences.value = references;
  showReferences.value = true;
}

const selectReference = (ref: any) => {
  selectedReference.value = ref
  showDialog({
    title: '您即将离开witdata，跳转到第三方网站',
    message: 'witdata出于为您提供便利的目的向您提供第三方链接，我们不对第三方网站的内容负责，请您审慎访问，保护好您的信息及财产安全。',
    showCancelButton: true,
    cancelButtonText: '取消',
    confirmButtonText: '继续访问',
    confirmButtonColor: '#4080ff',
  }).then(() => {
    showExternalSite.value = true
    showReferences.value = false
  }).catch(() => {
  })
}

const closeExternalSite = () => {
  showExternalSite.value = false
}
</script>

<template>
  <div class="ai-search-container">
    <div class="header">
      <div class="back-button" @click="goBack">
        <Icon name="arrow-left" size="24" />
      </div>
      <div class="title">AI搜索</div>
      <div class="right-button" @click="clearHistory">
        <div class="clear-button">
          <Icon name="delete-o" size="16" />
          <span>清空</span>
        </div>
      </div>
    </div>

    <div class="chat-content" ref="chatContent">
      <WelcomeMessage v-if="historyMessages.length === 0" />
      
      <MessageList
        v-else
        :messages="historyMessages"
        :loading="loading"
        @open-references="openReferences"
      />
    </div>
    
    <SearchInput
      :loading="loading"
      @search="handleSearch"
      @stop="handleStopStream"
    />

    <ReferenceMaterial
      :show="showReferences"
      @update:show="showReferences = $event"
      :references="selectedReferences"
      @select="selectReference"
    />
    
    <Popup
      v-model:show="showExternalSite"
      position="right"
      :style="{ width: '100%', height: '100%' }"
    >
      <WebBrowser
        v-if="showExternalSite"
        :title="selectedReference?.title"
        :url="selectedReference?.url"
        @close="closeExternalSite"
      />
    </Popup>
  </div>
</template>

<style lang="scss" scoped>
.ai-search-container {
  display: flex;
  flex-direction: column;
  height: 100vh;
  background-color: #f7f8fa;
  position: relative;
  overflow: hidden;
  
  .header {
    display: flex;
    align-items: center;
    padding: 12px 16px;
    background-color: #ffffff;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
    position: sticky;
    top: 0;
    left: 0;
    right: 0;
    z-index: 10;
    
    .back-button {
      padding: 8px;
      display: flex;
      align-items: center;
      justify-content: center;
      color: #333;
      border-radius: 50%;
      
      &:active {
        background-color: rgba(0, 0, 0, 0.05);
      }
    }
    
    .title {
      flex: 1;
      text-align: center;
      font-size: 18px;
      font-weight: 500;
      color: #333;
    }
    
    .right-button {
      .clear-button {
        display: flex;
        align-items: center;
        gap: 4px;
        padding: 6px 12px;
        background-color: #f5f5f5;
        border-radius: 16px;
        color: #666;
        font-size: 14px;
        
        &:active {
          background-color: #e8e8e8;
        }
      }
    }
  }
  
  .chat-content {
    flex: 1;
    overflow-y: auto;
    padding: 16px;
    padding-bottom: 60px;
  }
}

@keyframes fadeIn {
  from { opacity: 0.7; }
  to { opacity: 1; }
}
</style>
